package com.maezia.tdr.common;

import cn.hutool.http.Header;
import com.alibaba.fastjson.JSONObject;
import com.maezia.tdr.common.enums.RedisMessageEnum;
import com.maezia.tdr.common.enums.SwitchTypeEnum;
import com.maezia.tdr.common.exception.TokenExpiredException;
import com.maezia.tdr.common.redis.BaseRedisRepository;
import com.maezia.tdr.domain.po.ClientDetails;
import com.maezia.tdr.domain.po.Dict;
import com.maezia.tdr.domain.po.RequestLog;
import com.maezia.tdr.service.DictService;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Aspect
@Component
public class LoggingAspect extends BaseRedisRepository<String> {

    private static String LOGGING_SWITCH_KEY = "LOGGING_SWITCH";

    @Autowired
    private DictService dictService;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    public LoggingAspect() {
        super(String.class);
    }

    @Pointcut("@annotation(com.maezia.tdr.common.annotation.Loggable)")
    public void doPointcut(){}

    @Before("doPointcut()")
    public void doBefore(JoinPoint joinPoint) throws TokenExpiredException {
        Dict dict = dictService.getByKey(LOGGING_SWITCH_KEY);
        if(!ObjectUtils.isEmpty(dict) && SwitchTypeEnum.ON.getCode() == Integer.valueOf(dict.getValue())){
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            Map<String, Object> paramMap = new LinkedHashMap<>();
            Object[] methodArgs = joinPoint.getArgs();
            for (int i = 0; i < methodArgs.length; i++) {
                Object argValue = methodArgs[i];
                String parameterName = ((MethodSignature) joinPoint.getSignature()).getParameterNames()[i];
                paramMap.put(parameterName, argValue);
            }
            String requestUrl = request.getRequestURI();
            String method = request.getMethod();
            String tokenValue = request.getHeader(Header.AUTHORIZATION.getValue());
            String token = StringUtils.isEmpty(tokenValue) ? Strings.EMPTY : tokenValue.substring(CommonConstant.TOKEN_PREFIX_VALUE.length());
            ClientDetails userInfo = StringUtils.isEmpty(token) ? null : jwtTokenProvider.getUserInfo(token, ClientDetails.class);

            RequestLog requestLog = new RequestLog();
            requestLog.setRequestUrl(requestUrl);
            requestLog.setClientId(ObjectUtils.isEmpty(userInfo) ? null : userInfo.getClientId());
            requestLog.setMethod(method);
            requestLog.setRequestParam(JSONObject.toJSONString(paramMap));
            stringRedisTemplate.convertAndSend(RedisMessageEnum.LOGGING_POCESSING_SERVICE.getName(), JSONObject.toJSONString(requestLog));
        }
    }
}
